package redis

import (
	"encoding/json"
	"github.com/edgexfoundry/edgex-go/internal/app/models"
	"github.com/edgexfoundry/edgex-go/internal/app/pkg/controller/http"
	"github.com/edgexfoundry/edgex-go/internal/app/pkg/utils"
	"github.com/edgexfoundry/go-mod-core-contracts/v2/common"
	"github.com/edgexfoundry/go-mod-core-contracts/v2/errors"
	"github.com/gomodule/redigo/redis"
	"time"
)

const (
	TransportCollection       = DeviceCollection + DBKeySeparator + Transport
	TransportDeviceCollection = DeviceCollection + DBKeySeparator + Transport + DBKeySeparator + common.Device
)

// transportsGetByDeviceId Transport get by device id
func transportsGetByDeviceId(conn redis.Conn, deviceId string, offset, limit int) ([]models.Transport, errors.EdgeX) {
	storedKey := CreateKey(TransportDeviceCollection, deviceId)
	objects, edgeXerr := getObjectsByRevRange(conn, storedKey, offset, limit)
	if edgeXerr != nil {
		return nil, errors.NewCommonEdgeXWrapper(edgeXerr)
	}

	transports := make([]models.Transport, len(objects))
	for index, obj := range objects {
		var event models.Transport
		err := json.Unmarshal(obj, &event)
		if err != nil {
			continue
		}

		transports[index] = event
	}
	return transports, nil
}

// transportAdd 添加传输配置
func transportAdd(conn redis.Conn, deviceId string, transports ...models.Transport) (err errors.EdgeX) {
	deviceTransportKey := CreateKey(TransportDeviceCollection, deviceId)

	_ = conn.Send(MULTI)
	for _, transport := range transports {

		if transport.Id == "" {
			transport.Id, _ = utils.GenerateUUID()
		}
		s, errJson := json.Marshal(transport)
		if errJson != nil {
			return errors.NewCommonEdgeX(errors.KindServerError, http.ParamsError, errJson)
		}
		transportKey := CreateKey(TransportCollection, transport.Id)
		_ = conn.Send(SET, transportKey, s)
		_ = conn.Send(ZADD, deviceTransportKey, time.Now().UnixMilli(), transportKey)
	}
	_ = conn.Send(EXEC)
	return nil
}

// transportDelete transport delete
func transportDelete(conn redis.Conn, deviceId string, keys ...string) errors.EdgeX {
	for _, transportKey := range keys {
		err := checkTransportExist(conn, transportKey)
		if err != nil {
			return err
		}
	}

	deviceTransportKey := CreateKey(TransportDeviceCollection, deviceId)
	_ = conn.Send(MULTI)
	for _, transportKey := range keys {
		transportKey := CreateKey(TransportCollection, transportKey)
		_ = conn.Send(DEL, transportKey)
		_ = conn.Send(ZREM, deviceTransportKey, transportKey)
	}
	_ = conn.Send(EXEC)
	return nil
}

// transportUpdate 自动采集update
func transportUpdate(conn redis.Conn, deviceId string, transport models.Transport) errors.EdgeX {

	origin, err := transportGetById(conn, transport.Id)
	if err != nil {
		return err
	}
	origin.Name = transport.Name
	origin.Type = transport.Type
	origin.Topic = transport.Topic
	origin.Description = transport.Description

	deviceTransportKey := CreateKey(TransportDeviceCollection, deviceId)
	_ = conn.Send(MULTI)

	s, errJson := json.Marshal(origin)
	if errJson != nil {
		return errors.NewCommonEdgeX(errors.KindServerError, http.ParamsError, errJson)
	}
	transportKey := CreateKey(TransportCollection, transport.Id)
	_ = conn.Send(SET, transportKey, s)
	_ = conn.Send(ZADD, deviceTransportKey, time.Now().UnixMilli(), transportKey)
	_ = conn.Send(EXEC)
	return nil
}

func checkTransportExist(conn redis.Conn, id string) errors.EdgeX {
	exists, err := transportExist(conn, id)
	if err != nil {
		return errors.NewCommonEdgeX(errors.Kind(err), http.DataBaseQueryError, err)
	} else if !exists {
		return errors.NewCommonEdgeX(errors.KindInvalidId, http.TransportDeleteNotExist, nil)
	}
	return nil
}

// transportExist 传输配置是否存在
func transportExist(conn redis.Conn, eventId string) (bool, errors.EdgeX) {
	return objectIdExists(conn, CreateKey(TransportCollection, eventId))
}

// transportGetById 根据id查询自动采集
func transportGetById(conn redis.Conn, eventId string) (models.Transport, errors.EdgeX) {
	var event models.Transport
	err := getObjectById(conn, CreateKey(TransportCollection, eventId), &event)
	if err != nil {
		return event, err
	}
	return event, nil
}
